package com.mmm.station.activiti.service;


import com.mmm.station.activiti.entity.CompleteBean;
import com.mmm.station.activiti.entity.SysLeave;
import com.mmm.station.activiti.entity.TaskBean;
import com.mmm.station.activiti.entity.WorkflowBean;
import com.mmm.station.activiti.mapper.SysLeaveDao;
import com.mmmm.station.security.utils.ContextHolderUtils;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * Created by mmm on 2016/10/17.
 */
@Service
public class WorkflowService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
//    @Autowired
//    private FormService formService;

    @Autowired
    private SysLeaveDao sysLeaveDao;

//    @Autowired
//    private SysUserDao sysUserDao;

    /**
     * 部署流程
     *
     * @param
     */
    public int newdeploy(MultipartFile file) {


//        InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloworld.zip");

        String fileName = file.getOriginalFilename();
        String contextPath = ContextHolderUtils.getContextPath();
        File file1 = new File(contextPath+fileName);
        FileInputStream inn = null;
        try {
            file.transferTo(file1);
            inn = new FileInputStream(file1);
//            inn = new FileInputStream(ContextHolderUtils.getRequest().getServletContext().getRealPath("/")+"diagrams/helloworld.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inn);
        Deployment deployment = repositoryService//与流程定义和部署对象相关的Service
                .createDeployment()//创建一个部署对象
                .name("mmm")//添加部署的名称
                .addZipInputStream(zipInputStream)//指定zip格式的文件完成部署
                .deploy();//完成部署
        System.out.println("部署ID："+deployment.getId());//
        System.out.println("部署名称："+deployment.getName());//
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inn.close();
            } catch (IOException e) {
//                e.printStackTrace();
                System.out.println("部署错误");
            }
            new File(contextPath+fileName).delete();
        }







//        Deployment deployment = repositoryService//与流程定义和部署对象相关的Service
//                .createDeployment()//创建一个部署对象
//                .name("mmm")//添加部署的名称
//                .addClasspathResource("process/choiceFlow.bpmn")//从classpath的资源中加载，一次只能加载一个文件
//                .addClasspathResource("process/choiceFlow.png")//从classpath的资源中加载，一次只能加载一个文件
//                .deploy();//完成部署
//        System.out.println("部署ID：" + deployment.getId());//
//        System.out.println("部署名称：" + deployment.getName());//
        return 1;
    }






    /**
     * 查询流程定义
     */
    public List<WorkflowBean> findProcessDefinition() {
        List<ProcessDefinition> list = repositoryService//与流程定义和部署对象相关的Service
                .createProcessDefinitionQuery()//创建一个流程定义的查询
                /**指定查询条件,where条件*/
//						.deploymentId(deploymentId)//使用部署对象ID查询
//						.processDefinitionId(processDefinitionId)//使用流程定义ID查询
//						.processDefinitionKey(processDefinitionKey)//使用流程定义的key查询
//						.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询

                /**排序*/
                .orderByProcessDefinitionVersion().asc()//按照版本的升序排列
//						.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列

                /**返回的结果集*/
                .list();//返回一个集合列表，封装流程定义
//						.singleResult();//返回惟一结果集
//						.count();//返回结果集数量
//						.listPage(firstResult, maxResults);//分页查询


/** 查询最新版的额流程定义*/
//        Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
//        if(list!=null && list.size()>0){
//            for(ProcessDefinition pd:list){
//                map.put(pd.getKey(), pd);
//            }
//        }
//        List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values());


        List<WorkflowBean> workflowBeanlist = new ArrayList<WorkflowBean>();

        if (list != null && list.size() > 0) {
            for (ProcessDefinition pd : list) {
                WorkflowBean workflowBean = new WorkflowBean();
                workflowBean.setProcessId(pd.getId());
                workflowBean.setProcessName(pd.getName());
                workflowBean.setProcessKey(pd.getKey());
                workflowBean.setProcessVersion(pd.getVersion());
                workflowBean.setDeploymentId(pd.getDeploymentId());
                workflowBean.setImageName(pd.getDiagramResourceName());
                workflowBean.setResourcesName(pd.getResourceName());

                workflowBeanlist.add(workflowBean);
                System.out.println("流程定义ID:" + pd.getId());//流程定义的key+版本+随机生成数
                System.out.println("流程定义的名称:" + pd.getName());//对应helloworld.bpmn文件中的name属性值
                System.out.println("流程定义的key:" + pd.getKey());//对应helloworld.bpmn文件中的id属性值
                System.out.println("流程定义的版本:" + pd.getVersion());//当流程定义的key值相同的相同下，版本升级，默认1
                System.out.println("资源名称bpmn文件:" + pd.getResourceName());
                System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
                System.out.println("部署对象ID：" + pd.getDeploymentId());
                System.out.println("#########################################################");
            }
        }

        return workflowBeanlist;
    }


    /**
     * 删除流程定义
     */
    public void deleteProcessDefinition(String deploymentId) {
        //使用部署ID，完成删除
//        String deploymentId = "601";
        /**
         * 不带级联的删除
         *    只能删除没有启动的流程，如果流程启动，就会抛出异常
         */
//		processEngine.getRepositoryService()//
//						.deleteDeployment(deploymentId);

        /**
         * 级联删除
         * 	  不管流程是否启动，都能可以删除
         */
        repositoryService//
                .deleteDeployment(deploymentId, true);
        System.out.println("删除成功！");
    }


    /**
     * 使用部署对象ID和资源图片名称，获取图片的输入流
     */
    public InputStream findImageInputStream(String deploymentId,
                                            String imageName) {
        return repositoryService.getResourceAsStream(deploymentId, imageName);
    }


    /**
     * 启动流程实例，让启动的流程实例关联业务
     */
    public void saveStartProcess(String processKey, SysLeave sysLeave) {
        /**
         * ：从Session中获取当前任务的办理人，使用流程变量设置下一个任务的办理人
         * user是流程变量的名称，
         * 获取的办理人是流程变量的值
         */
        int a = sysLeaveDao.insertSelective(sysLeave);
        if(a>0){

            Map<String, Object> variables = new HashMap<String, Object>();
//            variables.put("user", ShiroUtils.getCurrentUser().getSysUserName());//表示惟一用户
            variables.put("user", "qe");//表示惟一用户
            /**
             *：	(1)使用流程变量设置字符串（格式：LeaveBill.id的形式），通过设置，让启动的流程（流程实例）关联业务
             (2)使用正在执行对象表中的一个字段BUSINESS_KEY（Activiti提供的一个字段），让启动的流程（流程实例）关联业务
             */
            //格式：LeaveBill.id的形式（使用流程变量）
            String objId = sysLeave.getClass().getSimpleName()+"."+sysLeave.getSysLeaveId();
            variables.put("objId", objId);
            //使用流程定义的key，启动流程实例，同时设置流程变量，同时向正在执行的执行对象表中的字段BUSINESS_KEY添加业务数据，同时让流程关联业务
            runtimeService.startProcessInstanceByKey(processKey, objId, variables);
        }
    }

    /**
     * ：获取当前任务的集合List<Task>
     */

    public Object findTaskListByName() {
//        String userName = ShiroUtils.getCurrentUser().getSysUserName();
        String userName = "sdf";

        List<Task> list = taskService.createTaskQuery()//
                .taskAssignee(userName)//指定个人任务查询
                .orderByTaskCreateTime().asc()//
                .list();
        List<Map> list1 = new ArrayList<Map>();
        List<TaskBean> list2 = new ArrayList<TaskBean>();
        if (list != null && list.size() > 0) {
            for (Task task : list) {
                Map map = new HashMap();
                map.put("任务ID", task.getId());
                map.put("任务名称", task.getName());
                map.put("任务的创建时间", task.getCreateTime());
                map.put("任务的办理人", task.getAssignee());
                map.put("流程实例ID", task.getProcessInstanceId());
                map.put("执行对象ID", task.getExecutionId());
                map.put("流程定义ID", task.getProcessDefinitionId());

                TaskBean taskBean = new TaskBean();

                taskBean.setTaskId(task.getId());
                taskBean.setTaskName(task.getName());
                taskBean.setAssignee(task.getAssignee());
                taskBean.setProcessBean(findBeanByTaskId(task.getId()));
                taskBean.setSubmitTime(task.getCreateTime());
                list2.add(taskBean);


                list1.add(map);
                System.out.println("任务ID:" + task.getId());
                System.out.println("任务名称:" + task.getName());
                System.out.println("任务的创建时间:" + task.getCreateTime());
                System.out.println("任务的办理人:" + task.getAssignee());
                System.out.println("流程实例ID：" + task.getProcessInstanceId());
                System.out.println("执行对象ID:" + task.getExecutionId());
                System.out.println("流程定义ID:" + task.getProcessDefinitionId());
                System.out.println("########################################################");
            }
        }


        return list2;
    }


    /**
     * 指定连线的名称完成任务
     */
    public void saveSubmitTask(CompleteBean completeBean) {

        /**
         * 1：在完成之前，添加一个批注信息，向act_hi_comment表中添加数据，用于记录对当前申请人的一些审核信息
         */
        String taskId = completeBean.getTaskId();
        //使用任务ID，查询任务对象，获取流程流程实例ID
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        //获取流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        /**
         * 注意：添加批注的时候，由于Activiti底层代码是使用：
         * 		String userId = Authentication.getAuthenticatedUserId();
         CommentEntity comment = new CommentEntity();
         comment.setUserId(userId);
         所有需要从Session中获取当前登录人，作为该任务的办理人（审核人），对应act_hi_comment表中的User_ID的字段，不过不添加审核人，该字段为null
         所以要求，添加配置执行使用Authentication.setAuthenticatedUserId();添加当前任务的审核人
         * */
        Authentication.setAuthenticatedUserId("wer");
//        Authentication.setAuthenticatedUserId(ShiroUtils.getCurrentUser().getSysUserName());
        taskService.addComment(taskId, processInstanceId, task.getName()+":"+completeBean.getRemark());
        /**
         * 2：如果连线的名称是“默认提交”，那么就不需要设置，如果不是，就需要设置流程变量
         * 在完成任务之前，设置流程变量，按照连线的名称，去完成任务
         流程变量的名称：outcome
         流程变量的值：连线的名称
         */
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("message", "总要");
        if(completeBean.getNextAssiginee() != null){
//            variables.put("user", sysUserDao.selectByKey(completeBean.getNextAssiginee()).getSysUserName());
        }else {
//            variables.put("user", ShiroUtils.getCurrentUser().getSysUserName());
        }

        //3：使用任务ID，完成当前人的个人任务，同时流程变量
        taskService.complete(taskId, variables);
        //4：当任务完成之后，需要指定下一个任务的办理人（使用类）-----已经开发完成

        /**
         * 5：在完成任务之后，判断流程是否结束
         如果流程结束了，更新请假单表的状态从1变成2（审核中-->审核完成）
         */
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();

        //流程结束了
        if (pi == null) {
            //更新业务单表的状态从1变成2（审核中-->审核完成）
            System.out.println("流程结束了");
        } else {
            System.out.println("流程正在进行中");
        }
    }


    /**
     * 使用ID，查询历史批注信息
     */

    public Object findComment(String businessKey) {

        //组织流程表中的字段中的值
//        String objId = "choice.1";
        /**1:使用历史的流程实例查询，返回历史的流程实例对象，获取流程实例ID*/
		HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()//对应历史的流程实例表
						.processInstanceBusinessKey(businessKey)//使用BusinessKey字段查询
						.singleResult();
//		//流程实例ID
		String processInstanceId = hpi.getId();
        List<Map> list1 = new ArrayList<Map>();
        List<Comment> list = taskService.getProcessInstanceComments(processInstanceId);
        if (list != null && list.size() > 0) {
            for (Comment comment : list) {
                Map map = new HashMap();
                map.put("FullMessage", comment.getFullMessage());
                map.put("Id", comment.getId());
                map.put("UserId", comment.getUserId());
                map.put("ProcessInstanceId", comment.getProcessInstanceId());
                map.put("TaskId", comment.getTaskId());
                map.put("Time", comment.getTime());
                map.put("Type", comment.getType());

                list1.add(map);

            }
        }



        /**2:使用历史的流程变量查询，返回历史的流程变量的对象，获取流程实例ID*/
//        List<HistoricVariableInstance> hvi = historyService.createHistoricVariableInstanceQuery()//对应历史的流程变量表
//                .variableValueEquals("objId", objId)//使用流程变量的名称和流程变量的值查询
//                .list();
//        //流程实例ID
//        List<Map> list1 = new ArrayList<>();
//        if (hvi != null && hvi.size() > 0) {
//            for (HistoricVariableInstance hvi1 : hvi) {
//                String processInstanceId = hvi1.getProcessInstanceId();
//                List<Comment> list = taskService.getProcessInstanceComments(processInstanceId);
//                if (list != null && list.size() > 0) {
//                    for (Comment comment : list) {
//                        Map map = new HashMap<>();
//                        map.put("FullMessage", comment.getFullMessage());
//                        map.put("Id", comment.getId());
//                        map.put("UserId", comment.getUserId());
//                        map.put("ProcessInstanceId", comment.getProcessInstanceId());
//                        map.put("TaskId", comment.getTaskId());
//                        map.put("Time", comment.getTime());
//                        map.put("Type", comment.getType());
//                        list1.add(map);
//
//                    }
//                }
//            }
//        }
        return list1;
    }


    /**
     * 一：使用任务ID，查找任务单ID，从而获取任务单信息
     */
    public Object findBeanByTaskId(String taskId) {
        //1：使用任务ID，查询任务对象Task
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        //2：使用任务对象Task获取流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        //3：使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        //4：使用流程实例对象获取BUSINESS_KEY
        String buniness_key = pi.getBusinessKey();
        //5：获取BUSINESS_KEY对应的主键ID，使用主键ID，查询请假单对象（LeaveBill.1）
        String id = "";
        if (StringUtils.isNotBlank(buniness_key)) {
            //截取字符串，取buniness_key小数点的第2个值
            id = buniness_key.split("\\.")[1];
        }


        Map map = new HashMap();
        map.put("deployName",pi.getProcessDefinitionName());



        //查询请假单对象
        //使用hql语句：from LeaveBill o where o.id=1
        SysLeave sysLeave = sysLeaveDao.selectByKey(Long.parseLong(id));
        sysLeave.setSysUserName("sfd");
//        sysLeave.setSysUserName(sysUserDao.selectByKey(sysLeave.getSysUserId()).getSysUserName());

        map.put("bean",sysLeave);

        return map;
    }

    /**
     * 通过businessKey 获取正在执行的taskId
     */

    public Task getTaskByBusinessKey(String businessKey){

       return taskService.createTaskQuery().processInstanceBusinessKey(businessKey).singleResult();
    }


    /**1：获取任务ID，获取任务对象，使用任务对象获取流程定义ID，查询流程定义对象*/
    public ProcessDefinition findProcessDefinitionByTaskId(String taskId) {
        //使用任务ID，查询任务对象
//       ProcessInstance pi =  runtimeService.createProcessInstanceQuery().processInstanceBusinessKey("").singleResult();
//        pi.

        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        //获取流程定义ID
        String processDefinitionId = task.getProcessDefinitionId();
        //查询流程定义的对象
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()//创建流程定义查询对象，对应表act_re_procdef
                .processDefinitionId(processDefinitionId)//使用流程定义ID查询
                .singleResult();
        return pd;
    }


    /**
     * 二：查看当前活动，获取当期活动对应的坐标x,y,width,height，将4个值存放到Map<String,Object>中
     map集合的key：表示坐标x,y,width,height
     map集合的value：表示坐标对应的值
     */
    public Map<String, Object> findCoordingByTask(String taskId) {
        //存放坐标
        Map<String, Object> map = new HashMap<String,Object>();
        //使用任务ID，查询任务对象
        Task task = taskService.createTaskQuery()//
                .taskId(taskId)//使用任务ID查询
                .singleResult();
        //获取流程定义的ID
        String processDefinitionId = task.getProcessDefinitionId();
        //获取流程定义的实体对象（对应.bpmn文件中的数据）
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processDefinitionId);
        //流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        //使用流程实例ID，查询正在执行的执行对象表，获取当前活动对应的流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//创建流程实例查询
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        //获取当前活动的ID
        String activityId = pi.getActivityId();
        //获取当前活动对象
        ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);//活动ID
        //获取坐标
        map.put("x", activityImpl.getX());
        map.put("y", activityImpl.getY());
        map.put("width", activityImpl.getWidth());
        map.put("height", activityImpl.getHeight());
        return map;
    }


}
